home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / misc / emu / msh-156.lha / han / pack.c < prev    next >
C/C++ Source or Header  |  1996-12-22  |  36KB  |  1,360 lines

  1. /*-
  2.  * $Id: pack.c,v 1.56 1996/12/22 00:22:33 Rhialto Rel $
  3.  * $Log: pack.c,v $
  4.  * Revision 1.56  1996/12/22  00:22:33  Rhialto
  5.  * Better (but not perfect) device list deadlock handling.
  6.  * Add some Guru Book packets.
  7.  * Pretend success on ACTION_SET_COMMENT.
  8.  * Support for proper taskwait hook.
  9.  *
  10.  * Revision 1.55  1993/12/30  23:02:45    Rhialto
  11.  * Add code to reflect changing disk capacity to Mount info.
  12.  * Don't fail Info() if there is no disk in drive.
  13.  * SameLock() was wrong because TADM was wrong.
  14.  * Add Format() packet.
  15.  * Use 2.0+ calls for manipulating the device list, if possible.
  16.  * New LONGNAMES filesystem, changes throughout the handler.
  17.  * Optional (compile-time) broadcast IECLASS_DISKINSERTED messages.
  18.  * Freeze for MAXON5.
  19.  *
  20.  * Revision 1.54  1993/06/24  05:12:49    Rhialto
  21.  * DICE 2.07.54R.
  22.  *
  23.  * Revision 1.53  92/10/25  02:23:50  Rhialto
  24.  * Add 2.0 stuff.
  25.  *
  26.  * Revision 1.51  92/04/17  15:34:59  Rhialto
  27.  * Freeze for MAXON. DosType->Interleave; extra uninhibits fixed.
  28.  *
  29.  * Revision 1.46  91/10/06  18:26:16  Rhialto
  30.  *
  31.  * Freeze for MAXON
  32.  *
  33.  * Revision 1.43  91/09/28  01:35:36  Rhialto
  34.  * Changed to newer syslog stuff.
  35.  *
  36.  * Revision 1.42  91/06/13  23:46:21  Rhialto
  37.  * DICE conversion
  38.  *
  39.  * Revision 1.40  91/03/03  17:45:09  Rhialto
  40.  * Freeze for MAXON
  41.  *
  42.  * Revision 1.32  90/11/23  23:53:22  Rhialto
  43.  * Prepare for syslog
  44.  *
  45.  * Revision 1.31  90/11/10  02:42:38  Rhialto
  46.  * Patch 3a.
  47.  *
  48.  * Revision 1.30  90/06/04  23:15:58  Rhialto
  49.  * Release 1 Patch 3
  50.  *
  51.  *  Originally:
  52.  *
  53.  *    DOSDEVICE.C        V1.10   2 November 1987
  54.  *
  55.  *    EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C    PUBLIC DOMAIN.
  56.  *
  57.  *    By Matthew Dillon.
  58.  *
  59.  *  This has been stripped and refilled with messydos code
  60.  *  by Olaf Seibert.
  61.  *
  62.  *  This code is (C) Copyright 1989-1992 by Olaf Seibert. All rights reserved.
  63.  *  May not be used or copied without a licence.
  64.  *
  65.  *  This file forms the interface between the actual handler code and all
  66.  *  AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
  67.  *  FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
  68.  *  Also, most protection against non-inserted disks is done here.
  69. -*/
  70.  
  71. #include "han.h"
  72. #include "dos.h"
  73. #include <string.h>
  74.  
  75. #if HDEBUG
  76. #   include "syslog.h"
  77. #else
  78. #   define    debug(x)
  79. #endif
  80.  
  81. #define MSFL(something)     ((struct MSFileLock *)(something))
  82. #define MSFH(something)     ((struct MSFileHandle *)(something))
  83.  
  84. Prototype struct MsgPort *DosPort;
  85. Prototype struct DeviceNode *DevNode;
  86. Prototype struct DeviceList *VolNode;
  87. Prototype short     DiskChanged;
  88. Prototype long        UnitNr;
  89. Prototype char       *DevName;
  90. Prototype ulong     DevFlags;
  91. Prototype long        Interleave;
  92. Prototype struct DosEnvec *Environ;
  93. Prototype struct DosPacket *DosPacket;
  94. Prototype short     Inhibited;
  95.  
  96. Prototype struct DeviceList *NewVolNode(char *name, struct DateStamp *date);
  97. Prototype int        MayFreeVolNode(struct DeviceList *volnode);
  98. Prototype void        FreeVolNode(struct DeviceList *volnode);
  99. Prototype void        FreeVolNodeDeferred(void);
  100. Prototype struct FileLock *NewFileLock(struct MSFileLock *msfl, struct FileLock *fl);
  101. Prototype long        FreeFileLock(struct FileLock *lock);
  102. Prototype long        DiskRemoved(void);
  103. Prototype void        DiskInserted(struct DeviceList *volnode);
  104. Prototype void        CheckDriveType(void);
  105. Prototype struct DeviceList *WhichDiskInserted(void);
  106. Prototype void        DiskChange(void);
  107. Prototype int        CheckRead(struct FileLock *lock);
  108. Prototype int        CheckWrite(struct FileLock *lock);
  109.  
  110. __stkargs /*__geta4*/ void ChangeIntHand(void);
  111. __stkargs void ChangeIntHand0(void);
  112. char *rega4(void);
  113. Local void NewVolNodeName(void);
  114. Local BPTR MakeFileLock(struct MSFileLock *msfl, struct FileLock *fl, long mode);
  115.  
  116. /*
  117.  * Since this code might be called several times in a row without being
  118.  * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  119.  * for any global/static assignments that might be changed by running the
  120.  * code.
  121.  */
  122.  
  123. struct MsgPort    *DosPort;    /* Our DOS port... */
  124. struct DeviceNode *DevNode;    /* Our DOS node.. created by DOS for us */
  125. struct DeviceList *VolNode;    /* Device List structure for our volume
  126.                  * node */
  127. struct DeviceList *MustFreeVolNode; /* Deferred free. Just place for one. */
  128.  
  129. struct DosLibrary *DOSBase;    /* DOS library base */
  130. long        PortMask;    /* The signal mask for our DosPort */
  131. long        WaitMask;    /* The signal mask to wait for */
  132. short        DiskChanged;    /* Set by disk change interrupt */
  133. short        Inhibited;    /* Are we inhibited (ACTION_INHIBIT)? */
  134. long        UnitNr;     /* From */
  135. char           *DevName;    /*   the */
  136. ulong        DevFlags;    /*     mountlist */
  137. long        Interleave;
  138. struct DosEnvec *Environ;
  139. struct DosPacket *DosPacket;    /* For the SystemRequest pr_WindowPtr */
  140. long        OpenCount;    /* How many open files/locks/other
  141.                  * references there are */
  142. short        WriteProtect;    /* Are we software-writeprotected? */
  143.  
  144. struct Interrupt ChangeInt = {
  145.     { 0 },            /* is_Node */
  146.     0,                /* is_Data */
  147.     ChangeIntHand0        /* is_Code */
  148. };
  149.  
  150. /*
  151.  * Don't call the entry point main().  This way, if you make a mistake
  152.  * with the compile options you'll get a link error.
  153.  */
  154.  
  155. void
  156. messydoshandler(void)
  157. {
  158.     struct DosPacket *packet;
  159. #if ! TASKWAIT
  160.     struct Message *msg;
  161. #endif
  162.     struct Process *myproc;
  163.     short        done;
  164.     struct FileSysStartupMsg *fssm;
  165.  
  166.     /*
  167.      * Initialize all global variables.  SysBase MUST be initialized
  168.      * before we can make Exec calls.  AbsExecBase is a library symbol
  169.      * referencing absolute memory location 4.
  170.      */
  171.  
  172.     DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0L);
  173.  
  174. #if HDEBUG
  175.     /*
  176.      * Initialize debugging code as soon as possible. Only SysBase required.
  177.      */
  178.  
  179.     initsyslog();
  180. #endif                /* HDEBUG */
  181.  
  182.     myproc = (struct Process *)FindTask(NULL);
  183.     DosPort = &myproc->pr_MsgPort;
  184.  
  185. #if TASKWAIT
  186.     packet = taskwait(myproc);
  187. #else
  188.     WaitPort(DosPort);        /* Get Startup Packet  */
  189.     msg = GetMsg(DosPort);
  190.     packet = (struct DosPacket *) msg->mn_Node.ln_Name;
  191. #endif
  192.  
  193.     DevNode = BTOC(PArg3);
  194.     {
  195.     ulong Reserved;
  196.  
  197.     DevName = "messydisk.device";
  198.     UnitNr = 0;
  199.     DevFlags = 0;
  200.  
  201.     MaxCache = 5;
  202.     BufMemType = MEMF_PUBLIC;
  203.     DefaultDisk.nsides = MS_NSIDES;
  204.     DefaultDisk.spt = MS_SPT;
  205.     DefaultDisk.bps = MS_BPS;
  206.     Partition.offset = 0;
  207.     Reserved = 0;
  208.     Interleave = 0;
  209.  
  210.     if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
  211.                     /* Same as BTOC(packet->dp_Arg2) */
  212.         UnitNr = fssm->fssm_Unit;
  213.         if (fssm->fssm_Device)
  214.         DevName = (char *)BTOC(fssm->fssm_Device)+1;
  215.         DevFlags = fssm->fssm_Flags;
  216.  
  217.         if (Environ = (void *)BTOC(fssm->fssm_Environ)) {
  218.         debug(("Environ size %ld\n", Environ->de_TableSize));
  219.  
  220.         if (Environ->de_TableSize >= DE_NUMBUFFERS) {
  221.             MaxCache = Environ->de_NumBuffers;
  222.  
  223.             DefaultDisk.nsides = Environ->de_Surfaces;
  224.             DefaultDisk.spt = Environ->de_BlocksPerTrack;
  225.             DefaultDisk.bps = Environ->de_SizeBlock * 4;
  226.             debug(("DefaultDisk.bps %ld\n", (long)DefaultDisk.bps));
  227.  
  228.             Partition.offset = Environ->de_LowCyl;
  229.             Reserved = Environ->de_Reserved;
  230.  
  231.             /* Compatibility with old DosType = 1 */
  232.             Interleave = Environ->de_DosType;
  233.             if (Interleave == 1) {
  234.             Interleave = NICE_TO_DFx;
  235.             } else {
  236.             Interleave = Environ->de_Interleave;
  237.             }
  238. #define get(xx,yy)  if (Environ->de_TableSize >= yy) xx = ((ULONG*)Environ)[yy];
  239.             get(BufMemType, DE_MEMBUFTYPE);
  240.         } else
  241.             Environ = NULL;
  242. #undef get
  243.         }
  244.     }
  245.     Disk = DefaultDisk;
  246.  
  247.     Partition.offset *= Disk.bps * Disk.spt * Disk.nsides;
  248.     Partition.offset += Disk.bps * Reserved;
  249.  
  250.     /* These values are used only for floppies (i.e. DRIVE*) */
  251.     if (Disk.spt <= MS_SPT_MAX_DD) {
  252.         Partition.spt_dd = Disk.spt;
  253.         Partition.spt_hd = Disk.spt * 2;
  254.     } else {
  255.         Partition.spt_hd = Disk.spt;
  256.         Partition.spt_dd = Disk.spt / 2;
  257.     }
  258.  
  259.     debug(("offset %x, spt_dd %d, spt_hd %d\n",
  260.            Partition.offset, Partition.spt_dd, Partition.spt_hd));
  261.     }
  262.  
  263.     if (DOSBase && HanOpenUp()) {
  264.     /*
  265.      * Loading DevNode->dn_Task causes DOS *NOT* to startup a new
  266.      * instance of the device driver for every reference.    E.G. if
  267.      * you were writing a CON: device you would want this field to be
  268.      * NULL.
  269.      */
  270.  
  271.     DevNode->dn_Task = DosPort;
  272.  
  273.     PRes1 = DOSTRUE;
  274.     PRes2 = 0;
  275.     } else {            /* couldn't open dos.library  */
  276.     PRes1 = DOSFALSE;
  277.     PRes2 = ERROR_DEVICE_NOT_MOUNTED;   /* no better message available */
  278.     returnpacket(packet);
  279.     goto exit;        /* exit process    */
  280.     }
  281.     debug(("Returning startup packet %lx\n", packet));
  282.     returnpacket(packet);
  283.  
  284.     /* Initialize some more global variables    */
  285.  
  286.     PortMask = 1L << DosPort->mp_SigBit;
  287.     VolNode = NULL;
  288.     WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
  289.     ChangeInt.is_Data = rega4();    /* for PURE code */
  290.     TDAddChangeInt(&ChangeInt);
  291.     OpenCount = 0;
  292.     Inhibited = 0;
  293.  
  294.     /* Get the first real packet       */
  295.     debug(("Awaiting first real dos packet\n"));
  296. #if TASKWAIT
  297.     packet = taskwait(myproc);
  298.     debug(("got it: %lx\n", packet));
  299. #else
  300.     WaitPort(DosPort);
  301.     msg = GetMsg(DosPort);
  302.     debug(("got it: %lx\n", msg));
  303. #endif
  304.     done = -1;
  305.     DiskInserted(WhichDiskInserted());
  306.  
  307.     goto entry;
  308.  
  309.     /*
  310.      * Here begins the endless loop, waiting for requests over our message
  311.      * port and executing them.  Since requests are sent over the message
  312.      * port in our device and volume nodes, we must not use our Process
  313.      * message port for this: this precludes being able to call DOS
  314.      * functions ourselves.
  315.      */
  316.  
  317. top:
  318.     for (done = -1; done < 0;) {
  319.     Wait(WaitMask);
  320.     if (DiskChanged)
  321.         DiskChange();
  322. #if TASKWAIT
  323.     while (packetsqueued()) {    /* } */
  324. #else
  325.     while (msg = GetMsg(DosPort)) {
  326. #endif
  327.         byte        buf[256];    /* Max length of BCPL strings is
  328.                      * 255 + 1 for \0. */
  329. #if TASKWAIT
  330.         packet = taskwait(myproc);
  331. #endif
  332.     entry:
  333.         if (MustFreeVolNode)
  334.         FreeVolNodeDeferred();
  335.         if (DiskChanged)
  336.         DiskChange();
  337.  
  338. #if ! TASKWAIT
  339.         packet = (PACKET *) msg->mn_Node.ln_Name;
  340. #endif
  341.         PRes1 = DOSFALSE;
  342.         PRes2 = 0;
  343.         error = 0;
  344.         debug(("Packet: %4ld %08lx %08lx %08lx %s\n",
  345.              PType, PArg1, PArg2, PArg3, typetostr(PType)));
  346.  
  347.         DosPacket = packet;     /* For the System Requesters */
  348.         switch (PType) {
  349.         case ACTION_DIE:        /* attempt to die?  */
  350.         done = (PArg1 == MSH_MAGIC) ? PArg2 : 0;   /* Argh! Hack! */
  351.         break;
  352.         case ACTION_CURRENT_VOLUME: /* fharg1,Magic,Count -> VolNode,UnitNr,Private */
  353.         if (PArg2 == MSH_MAGIC) {
  354.             PArg2 = (long)PrivateInfo();
  355.             if (PArg3 > 0) {
  356.             OpenCount++;
  357.             } else if (PArg3 < 0) {
  358.             OpenCount--;
  359.             }
  360.         }
  361.         PRes1 = (long) CTOB(VolNode);
  362.         PRes2 = UnitNr;
  363.         break;
  364.         case ACTION_LOCATE_OBJECT:    /* Lock,Name,Mode    Lock         */
  365.         {
  366.             struct FileLock *lock;
  367.             struct MSFileLock *msfl;
  368.             long        lockmode;
  369.  
  370.             lock = BTOC(PArg1);
  371.             if (CheckRead(lock))
  372.             break;
  373.             btos((byte *)PArg2, buf);
  374.             if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
  375.             lockmode = SHARED_LOCK;
  376.             msfl = MSLock(MSFL(lock ? lock->fl_Key : 0),
  377.                   buf,
  378.                   lockmode);
  379.             PRes1 = MakeFileLock(msfl, lock, lockmode);
  380.         }
  381.         break;
  382.         case ACTION_RENAME_DISK:    /* BSTR:NewName        Bool      */
  383.         if (CheckWrite(NULL))
  384.             break;
  385.         btos((byte *)PArg1, buf);
  386.         buf[31] = '\0';
  387.         if (PRes1 = MSRelabel(buf))
  388.             NewVolNodeName();
  389.         break;
  390.         case ACTION_FREE_LOCK:    /* Lock            Bool      */
  391.         {
  392.             struct FileLock *lock;
  393.             struct MSFileLock *msfl;
  394.  
  395.             PRes1 = DOSTRUE;
  396.             lock = BTOC(PArg1);
  397.             if (lock == NULL)
  398.             break;
  399.  
  400.             msfl = MSFL(lock->fl_Key);
  401.             FreeFileLock(lock); /* may remove last lock on volume */
  402.             MSUnLock(msfl);    /* may call MayFreeVolNode */
  403.         }
  404.         break;
  405.         case ACTION_DELETE_OBJECT:    /* Lock,Name        Bool         */
  406.         {
  407.             struct FileLock *lock;
  408.  
  409.             lock = BTOC(PArg1);
  410.             if (CheckWrite(lock))
  411.             break;
  412.             btos((byte *)PArg2, buf);
  413.             PRes1 = MSDeleteFile(MSFL(lock ? lock->fl_Key : 0),
  414.                      buf);
  415.         }
  416.         break;
  417.         case ACTION_RENAME_OBJECT:    /* SLock,SName,DLock,DName   Bool    */
  418.         {
  419.             struct FileLock *slock, *dlock;
  420.             char         buf2[256];
  421.  
  422.             slock = BTOC(PArg1);
  423.             dlock = BTOC(PArg3);
  424.             if (CheckWrite(slock) || CheckWrite(dlock))
  425.             break;
  426.             btos((byte *)PArg2, buf);
  427.             btos((byte *)PArg4, buf2);
  428.             PRes1 = MSRename(MSFL(slock ? slock->fl_Key : 0),
  429.                      buf,
  430.                      MSFL(dlock ? dlock->fl_Key : 0),
  431.                      buf2);
  432.         }
  433.         break;
  434.         case ACTION_MORECACHE:    /* #BufsToAdd        bool,numbufs */
  435.         if ((MaxCache += (short) PArg1) <= 0) {
  436.             MaxCache = 1;
  437.         }
  438.         PRes1 = MaxCache;   /* observed behaviour in std filesystem */
  439.         PRes2 = MaxCache;   /* documented behaviour in manual */
  440.         debug(("Now %ld cache sectors\n", (long)MaxCache));
  441.         break;
  442.         case ACTION_COPY_DIR:    /* Lock            Lock      */
  443.         {
  444.             struct FileLock *lock;
  445.             struct MSFileLock *msfl;
  446.  
  447.             lock = BTOC(PArg1);
  448.  
  449.             msfl = MSDupLock(MSFL(lock ? lock->fl_Key : 0));
  450.  
  451.             PRes1 = MakeFileLock(msfl, lock,
  452.                      lock ? lock->fl_Access : SHARED_LOCK);
  453.         }
  454.         break;
  455.         case ACTION_SET_PROTECT:    /* -,Lock,Name,Mask       Bool      */
  456.         {
  457.             struct FileLock *lock;
  458.  
  459.             lock = BTOC(PArg2);
  460.             if (CheckWrite(lock))
  461.             break;
  462.             btos((byte *)PArg3, buf);
  463.             PRes1 = MSSetProtect(MSFL(lock ? lock->fl_Key : 0),
  464.                     buf, PArg4);
  465.         }
  466.         break;
  467.         case ACTION_CREATE_DIR:    /* Lock,Name        Lock         */
  468.         {
  469.             struct FileLock *lock;
  470.             struct MSFileLock *msfl;
  471.  
  472.             lock = BTOC(PArg1);
  473.             if (CheckWrite(lock))
  474.             break;
  475.             btos((byte *)PArg2, buf);
  476.  
  477.             msfl = MSCreateDir(MSFL(lock ? lock->fl_Key : 0),
  478.                        buf);
  479.  
  480.             PRes1 = MakeFileLock(msfl, lock, SHARED_LOCK);
  481.         }
  482.         break;
  483.         case ACTION_EXAMINE_OBJECT: /* Lock,Fib           Bool         */
  484.         {
  485.             struct FileLock *lock;
  486.  
  487.             lock = BTOC(PArg1);
  488.             /*
  489.             if (CheckRead(lock))
  490.             break;
  491.             */
  492.             PRes1 = MSExamine(MSFL(lock ? lock->fl_Key : 0),
  493.                       BTOC(PArg2));
  494.         }
  495.         break;
  496.         case ACTION_EXAMINE_NEXT:    /* Lock,Fib           Bool         */
  497.         {
  498.             struct FileLock *lock;
  499.  
  500.             lock = BTOC(PArg1);
  501.             if (CheckRead(lock))
  502.             break;
  503.             PRes1 = MSExNext(MSFL(lock ? lock->fl_Key : 0),
  504.                      BTOC(PArg2));
  505.         }
  506.         break;
  507.         case ACTION_DISK_INFO:    /* InfoData           Bool:TRUE     */
  508.         PRes1 = MSDiskInfo(BTOC(PArg1));
  509.         break;
  510.         case ACTION_INFO:    /* Lock,InfoData           Bool:TRUE     */
  511.         if (CheckRead(BTOC(PArg1)))
  512.             break;
  513.         PRes1 = MSDiskInfo(BTOC(PArg2));
  514.         break;
  515.         case ACTION_FLUSH:        /* writeout bufs, disk motor off     */
  516.         MSUpdate(1);
  517.         break;
  518.         case ACTION_SET_COMMENT:    /* -,Lock,Name,Comment       Bool      */
  519.         /* pretend to succeed so that COPY CLONE does not give up */
  520.         PRes1 = DOSTRUE;
  521.         break;
  522.         case ACTION_PARENT: /* Lock                ParentLock    */
  523.         {
  524.             struct FileLock *lock;
  525.             struct MSFileLock *msfl;
  526.  
  527.             lock = BTOC(PArg1);
  528.  
  529.             msfl = MSParentDir(MSFL(lock ? lock->fl_Key : 0));
  530.  
  531.             PRes1 = MakeFileLock(msfl, lock, SHARED_LOCK);
  532.         }
  533.         break;
  534.         case ACTION_INHIBIT:    /* Bool            Bool      */
  535.         if (PArg1) {
  536.             ++Inhibited;
  537.             if (Inhibited == 1)
  538.             DiskRemoved();
  539.             IDDiskType = 'BUSY';/* GURU book p. 443 */
  540.         } else {
  541.             --Inhibited;
  542.             if (Inhibited < 0) {
  543.             Inhibited = 0;    /* Do nothing if already uninhibited */
  544.             } else if (Inhibited == 0) {
  545.             DiskChange();
  546.             }
  547.         }
  548.         PRes1 = DOSTRUE;
  549.         error = 0;
  550.         break;
  551.         case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp       Bool      */
  552.         {
  553.             struct FileLock *lock;
  554.  
  555.             lock = BTOC(PArg2);
  556.             if (CheckWrite(lock))
  557.             break;
  558.             btos((byte *)PArg3, buf);
  559.             PRes1 = MSSetDate(MSFL(lock ? lock->fl_Key : 0),
  560.                       buf,
  561.                       (struct DateStamp *)PArg4);
  562.         }
  563.         break;
  564. #ifdef ACTION_SAME_LOCK
  565.         case ACTION_SAME_LOCK:  /* Lock1,Lock2           Result    */
  566.         {
  567.             struct FileLock *fl1, *fl2;
  568.  
  569.             fl1 = BTOC(PArg1);
  570.             fl2 = BTOC(PArg2);
  571.             if (fl1->fl_Volume == fl2->fl_Volume) {
  572.             PRes1 = MSSameLock(MSFL(fl1->fl_Key),
  573.                        MSFL(fl2->fl_Key));
  574.             } else {
  575.             PRes1 = DOSFALSE;
  576.             error = ERROR_DEVICE_NOT_MOUNTED;
  577.             }
  578.         }
  579.         break;
  580. #endif
  581.         case ACTION_READ:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  582.         if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
  583.             CheckRead(NULL)) {
  584.             PRes1 = -1;
  585.         } else
  586.             PRes1 = MSRead(MSFH(PArg1), (byte *)PArg2, PArg3);
  587.         break;
  588.         case ACTION_WRITE:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  589.         if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
  590.             CheckWrite(NULL)) {
  591.             PRes1 = -1;
  592.         } else
  593.             PRes1 = MSWrite(MSFH(PArg1), (byte *)PArg2, PArg3);
  594.         break;
  595.         case ACTION_FINDUPDATE:    /* FileHandle,Lock,Name    Bool      */
  596.         case ACTION_FINDINPUT:    /* FileHandle,Lock,Name    Bool      */
  597.         goto open_notnew;
  598.         case ACTION_FINDOUTPUT:    /* FileHandle,Lock,Name    Bool      */
  599.         {
  600.             struct MSFileHandle *msfh;
  601.             struct FileHandle *fh;
  602.             struct FileLock *lock;
  603.  
  604.             if (CheckWrite(BTOC(PArg2)))
  605.             break;
  606.  
  607.         open_notnew:
  608.             fh = BTOC(PArg1);
  609.             lock = BTOC(PArg2);
  610.             if (CheckRead(lock))
  611.             break;
  612.             btos((byte *)PArg3, buf);
  613.             debug(("'%s' ", buf));
  614.             msfh = MSOpen(MSFL(lock ? lock->fl_Key : 0),
  615.                   buf,
  616.                   PType);
  617.             if (msfh) {
  618.             fh->fh_Arg1 = (long) msfh;
  619.             PRes1 = DOSTRUE;
  620.             OpenCount++;
  621.             }
  622.         }
  623.         break;
  624.         case ACTION_END:    /* FHArg1            Bool:Success */
  625.         PRes1 = MSClose(MSFH(PArg1));
  626.         OpenCount--;
  627.         break;
  628.         case ACTION_SEEK:    /* FHArg1,Position,Mode      OldPosition */
  629.         if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
  630.             CheckRead(NULL)) {
  631.             PRes1 = -1;
  632.         } else
  633.             PRes1 = MSSeek(MSFH(PArg1), PArg2, PArg3);
  634.         break;
  635.         case ACTION_FORMAT: /* vol,type            Bool:success */
  636.         btos((byte *)PArg1, buf);
  637.         PRes1 = MSFormat(buf, PArg2);
  638.         break;
  639. #ifdef ACTION_SET_FILE_SIZE    /* FHArg1, off, whence        Bool:success */
  640.         case ACTION_SET_FILE_SIZE:
  641.         PRes1 = MSSetFileSize(MSFH(PArg1), PArg2, PArg3);
  642.         break;
  643. #endif
  644. #ifdef ACTION_WRITE_PROTECT    /* Bool:protect, passkey    Bool:success */
  645.         case ACTION_WRITE_PROTECT:
  646.         {
  647.             static long     Passkey;
  648.  
  649.             if (PArg1) {
  650.             if (Passkey == 0) {
  651.                 WriteProtect = 1;
  652.                 Passkey = PArg2;
  653.                 PRes1 = DOSTRUE;
  654.             }
  655.             } else {
  656.             if (Passkey == 0 || PArg2 == Passkey) {
  657.                 WriteProtect = 0;
  658.                 Passkey = 0;
  659.                 PRes1 = DOSTRUE;
  660.             }
  661.             }
  662.         }
  663.         break;
  664. #endif
  665. #ifdef ACTION_FH_FROM_LOCK    /* FH,Lock                BOOL     */
  666.         case ACTION_FH_FROM_LOCK:
  667.         {
  668.             struct MSFileHandle *msfh;
  669.             struct FileHandle *fh;
  670.             struct FileLock *lock;
  671.  
  672.             fh = BTOC(PArg1);
  673.             lock = BTOC(PArg2);
  674.             if (CheckRead(lock))
  675.             break;
  676.             msfh = MSOpenFromLock(MSFL(lock ? lock->fl_Key : 0));
  677.             if (msfh) {
  678.             fh->fh_Arg1 = (long) msfh;
  679.             PRes1 = DOSTRUE;
  680.             OpenCount++;
  681.             /* Discard the lock */
  682.             FreeFileLock(lock);
  683.             }
  684.         }
  685.         break;
  686. #endif
  687. #ifdef ACTION_IS_FILESYSTEM
  688.         case ACTION_IS_FILESYSTEM:    /* -               Bool:TRUE */
  689.         PRes1 = DOSTRUE;
  690.         break;
  691. #endif
  692. #ifdef ACTION_CHANGE_MODE
  693.         case ACTION_CHANGE_MODE:
  694.         switch (PArg1) {
  695.         case CHANGE_FH:
  696.             PRes1 = MSChangeModeFH(MSFH(((struct FileHandle *)
  697.                 BTOC(PArg2))->fh_Arg1), PArg3);
  698.             break;
  699.         case CHANGE_LOCK:
  700.             PRes1 = MSChangeModeLock(MSFL(((struct FileLock *)
  701.                 BTOC(PArg2))->fl_Key), PArg3);
  702.             break;
  703.         }
  704.         break;
  705. #endif
  706. #ifdef ACTION_COPY_DIR_FH
  707.         case ACTION_COPY_DIR_FH:    /* fh_Arg1           Lock      */
  708.         case ACTION_PARENT_FH:
  709.         {
  710.             struct MSFileLock *msfl;
  711.  
  712.             if (PType == ACTION_PARENT_FH)
  713.             msfl = MSParentOfFH(MSFH(PArg1));
  714.             else
  715.             msfl = MSDupLockFromFH(MSFH(PArg1));
  716.             /*
  717.             msfl = ((PType == ACTION_PARENT_FH) ?
  718.                 MSParentOfFH : MSDupLockFromFH) (MSFH(PArg1));
  719.             */
  720.  
  721.             /* User has inserted disk by now, so we can use VolNode */
  722.             PRes1 = MakeFileLock(msfl, NULL, SHARED_LOCK);
  723.         }
  724.         break;
  725. #endif
  726. #ifdef ACTION_EXAMINE_FH
  727.         case ACTION_EXAMINE_FH:     /* fh_Arg1,Fib         Bool      */
  728.         PRes1 = MSExamineFH(MSFH(PArg1), BTOC(PArg2));
  729.         break;
  730. #endif
  731.         /* These packets by suggestion of the Amiga Guru Book: */
  732. #if defined(ACTION_SERIALIZE_DISK)
  733.         case ACTION_SERIALIZE_DISK:
  734.         PRes1 = MSSerializeDisk();
  735.         break;
  736. #endif
  737. #if defined(ACTION_GET_DISK_FSSM)
  738.         case ACTION_GET_DISK_FSSM:
  739.         PRes1 = (ULONG)fssm;
  740.         OpenCount++;
  741.         break;
  742.         case ACTION_FREE_DISK_FSSM:
  743.         PRes1 = DOSTRUE;
  744.         OpenCount--;
  745.         break;
  746. #endif
  747.         /*
  748.          * A few other packet types which we do not support
  749.          */
  750. /*        case ACTION_WAIT_CHAR:     / * Timeout, ticks       Bool      */
  751. /*        case ACTION_RAWMODE:       / * Bool(-1:RAW 0:CON)       OldState  */
  752.         default:
  753.         PRes1 = DOSFALSE;
  754.         error = ERROR_ACTION_NOT_KNOWN;
  755.         break;
  756.         } /* end switch */
  757.         if (packet) {
  758.         if (error)
  759.             PRes2 = error;
  760.         debug(("RES=%06lx, ERR=%ld\n", PRes1, error));
  761.         returnpacket(packet);
  762.         DosPacket = NULL;
  763.         }
  764. #if HDEBUG
  765.         else {
  766.         debug(("NO REPLY\n"));
  767.         }
  768. #endif
  769.     } /* end while (GetMsg()) */
  770.  
  771.     /*
  772.      *  Now check for an other cause of events: timer IO.
  773.      *  Unfortunately we cannot be sure that we always get a signal
  774.      *  when the timeout has elapsed, since the same message port is
  775.      *  used for other IO.
  776.      */
  777.     if (CheckIO(&TimeIOReq->tr_node)) {   /* Timer finished? */
  778.         debug(("TimeIOReq is finished\n"));
  779.         MSUpdate(0);    /* Also may switch off motor */
  780.     }
  781.     } /* end for (;done) */
  782.  
  783. #if HDEBUG
  784.     debug(("Can we remove ourselves? "));
  785. #endif                /* HDEBUG */
  786.     Forbid();
  787.     if (OpenCount || packetsqueued()) {
  788.     Permit();
  789.     debug((" ..  not yet!\n"));
  790.     goto top;        /* sorry... can't exit     */
  791.     }
  792.     debug((" .. yes!\n"));
  793.  
  794.     /*
  795.      * Causes a new process to be created on next reference.
  796.      */
  797.  
  798.     DevNode->dn_Task = NULL;
  799.     TDRemChangeInt();
  800.     DiskRemoved();
  801.     HanCloseDown();
  802.     debug(("HanCloseDown returned. uninitsyslog in 2 seconds:\n"));
  803.  
  804.     /*
  805.      * Remove debug, closedown, fall of the end of the world.
  806.      */
  807. exit:
  808. #if HDEBUG
  809.     Delay(100L);        /* This is dangerous! */
  810.     uninitsyslog();
  811. #endif                /* HDEBUG */
  812.  
  813.     if (done & 2)
  814.     UnLoadSeg(DevNode->dn_SegList); /* This is real fun. We are still */
  815.     if (done & (2 | 1))
  816.     DevNode->dn_SegList = 0;    /* Forbid()den, fortunately */
  817.  
  818.     CloseLibrary((struct Library *)DOSBase);
  819.  
  820.     /* Fall off the end of the world. Implicit Permit(). */
  821. }
  822.  
  823. /*
  824.  * ChangeIntHand must be __geta4 if it is called directly through the
  825.  * ChangeInt.is_Code pointer, but then we can't be pure.
  826.  * If ChangeIntHand0 is called, __geta4 is done there via is_Data.
  827.  */
  828.  
  829. __stkargs /*__geta4*/ void
  830. ChangeIntHand(void)
  831. {
  832.     DiskChanged = 1;
  833.     Signal(DosPort->mp_SigTask, PortMask);
  834. }
  835.  
  836. /*
  837.  *  Make a new struct FileLock, for DOS use. It is put on a singly linked
  838.  *  list, which is attached to the same VolumeNode the old lock was on.
  839.  *
  840.  *  Also note that we must ALWAYS be prepared to UnLock() or DupLock()
  841.  *  any FileLocks we ever made, even if the volume in question has been
  842.  *  removed and/or inserted into another drive with another FileSystem
  843.  *  handler!
  844.  *
  845.  * DOS makes certain assumptions about LOCKS.    A lock must minimally be a
  846.  * FileLock structure, with additional private information after the
  847.  * FileLock structure.    The longword before the beginning of the structure
  848.  * must contain the length of structure + 4.
  849.  *
  850.  * NOTE!!!!! The workbench does not follow the rules and assumes it can copy
  851.  * lock structures.  This means that if you want to be workbench
  852.  * compatible, your lock structures must be EXACTLY sizeof(struct
  853.  * FileLock). Also, it sometimes uses uninitialized values for the lock mode...
  854.  */
  855.  
  856. struct FileLock *
  857. NewFileLock(msfl, fl)
  858. struct MSFileLock *msfl;
  859. struct FileLock *fl;
  860. {
  861.     struct FileLock *newlock;
  862.     struct DeviceList *volnode = NULL;
  863.  
  864.     if (fl) {
  865.     volnode = BTOC(fl->fl_Volume);
  866.     }
  867.     if (volnode == NULL) {
  868.     volnode = VolNode;
  869.     debug(("volnode 0->%lx\n", volnode));
  870.     }
  871. #if HDEBUG
  872.     if (volnode != VolNode) {
  873.     debug(("volnode != VolNode %lx != %lx\n",
  874.         volnode, VolNode));
  875.     }
  876.     if (volnode->dl_Task != DosPort) {
  877.     debug(("volnode->dl_Task != DosPort %lx != %lx\n",
  878.         volnode->dl_Task, DosPort));
  879.     }
  880. #endif
  881.  
  882.     if (newlock = dosalloc((ulong)sizeof (*newlock))) {
  883.     newlock->fl_Key = (ulong) msfl;
  884.     newlock->fl_Task = DosPort;
  885.     newlock->fl_Volume = (BPTR) CTOB(volnode);
  886.     Forbid();
  887.     newlock->fl_Link = volnode->dl_LockList;
  888.     volnode->dl_LockList = (BPTR) CTOB(newlock);
  889.     Permit();
  890.     } else
  891.     error = ERROR_NO_FREE_STORE;
  892.  
  893.     return newlock;
  894. }
  895.  
  896. /*
  897.  *  This should be called before MSUnLock(), so that it may call
  898.  *  MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
  899.  *  I'm sorry for that.
  900.  */
  901.  
  902. long
  903. FreeFileLock(lock)
  904. struct FileLock *lock;
  905. {
  906.     struct FileLock *fl;
  907.     struct FileLock **flp;
  908.     struct DeviceList         *volnode;
  909.  
  910.     volnode = (struct DeviceList *)BTOC(lock->fl_Volume);
  911.     flp = (struct FileLock **) &volnode->dl_LockList;
  912.     for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
  913.     flp = (struct FileLock **)&fl->fl_Link;
  914.  
  915.     if (fl == lock) {
  916.     *(BPTR *)flp = fl->fl_Link;
  917.     dosfree((ulong *)fl);
  918.     OpenCount--;
  919.     return DOSTRUE;
  920.     } else {
  921.     debug(("Huh?? Could not find filelock!\n"));
  922.     return DOSFALSE;
  923.     }
  924. }
  925.  
  926. /*
  927.  * MakeFileLock allocates and initializes a new FileLock, using info
  928.  * from an existing FileLock. It always consumes the MSFileLock, even
  929.  * in case of failure.
  930.  */
  931.  
  932. BPTR
  933. MakeFileLock(msfl, fl, mode)
  934. struct MSFileLock *msfl;
  935. struct FileLock *fl;
  936. long        mode;
  937. {
  938.     struct FileLock *newlock;
  939.  
  940.     newlock = NULL;
  941.     if (msfl) {
  942.     if (newlock = NewFileLock(msfl, fl)) {
  943.         newlock->fl_Access = mode;
  944.         OpenCount++;
  945.     } else
  946.         MSUnLock(msfl);
  947.     }
  948.  
  949.     return CTOB(newlock);
  950. }
  951.  
  952. BOOL
  953. AddVolNode(struct DeviceList *volnode)
  954. {
  955.     long        success = DOSFALSE;
  956.  
  957.     if (DOSBase->dl_lib.lib_Version >= 37) {
  958.     struct DosList *dl;
  959.  
  960.     dl = AttemptLockDosList(LDF_VOLUMES | LDF_WRITE);
  961.     if ((ULONG)dl & ~1) {
  962.         success = AddDosEntry((struct DosList *)volnode);
  963.         UnLockDosList(LDF_VOLUMES | LDF_WRITE);
  964.     }
  965.     } else {
  966.     struct DosInfo *di;
  967.  
  968.     di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
  969.     Forbid();
  970.     volnode->dl_Next = di->di_DevInfo;
  971.     di->di_DevInfo = (long) CTOB(volnode);
  972.     Permit();
  973.     success = DOSTRUE;
  974.     }
  975.     return success;
  976. }
  977.  
  978. /*
  979.  * Create Volume node and add to the device list.   This will
  980.  * cause the WORKBENCH to recognize us as a disk.   If we
  981.  * don't create a Volume node, Wb will not recognize us.
  982.  * However, we are a MESSYDOS: disk, Volume node or not.
  983.  */
  984.  
  985. struct DeviceList     *
  986. NewVolNode(name, date)
  987. char *name;
  988. struct DateStamp *date;
  989. {
  990.     struct DeviceList *volnode;
  991.     char       *volname;        /* This is my volume name */
  992.  
  993.     if (volnode = dosalloc((ulong)sizeof (struct DeviceList))) {
  994.     if (volname = dosalloc(32L)) {
  995.         volname[0] = strlen(name);
  996.         strcpy(volname + 1, name);        /* Make sure \0 terminated */
  997.  
  998.         volnode->dl_Type = DLT_VOLUME;
  999.         volnode->dl_Task = DosPort;
  1000.         volnode->dl_DiskType = IDDiskType;
  1001.         volnode->dl_Name = (BSTR)CTOB(volname);
  1002.         volnode->dl_VolumeDate = *date;
  1003.         volnode->dl_MSFileLockList = (ULONG)NULL;
  1004.  
  1005.         if (AddDosEntry((struct DosList *)volnode)== DOSFALSE)
  1006.         goto error;
  1007.     } else {
  1008.     error:
  1009.         dosfree((ulong *)volnode);
  1010.         volnode = NULL;
  1011.     }
  1012.     } else {
  1013.     error = ERROR_NO_FREE_STORE;
  1014.     }
  1015.  
  1016.     return volnode;
  1017. }
  1018.  
  1019. /*
  1020.  *  Get the current VolNode a new name from the volume label.
  1021.  */
  1022.  
  1023. void
  1024. NewVolNodeName()
  1025. {
  1026.     if (VolNode) {
  1027.     char *volname = BTOC(VolNode->dl_Name);
  1028.  
  1029.     strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, L_8+L_3);
  1030.     ZapSpaces(volname + 1, volname + 1 + L_8+L_3);
  1031.     volname[0] = strlen(volname+1);
  1032.     }
  1033. }
  1034.  
  1035. /*
  1036.  * Remove Volume entry.  Since DOS uses singly linked lists, we must
  1037.  * (ugg) search it manually to find the link before our Volume entry.
  1038.  */
  1039.  
  1040. void
  1041. FreeVolNode(volnode)
  1042. struct DeviceList *volnode;
  1043. {
  1044.     int deallocate = 0;
  1045.  
  1046.     debug(("FreeVolNode %08lx\n", volnode));
  1047.  
  1048.     if (volnode == NULL)
  1049.     return;
  1050.  
  1051.     if (DOSBase->dl_lib.lib_Version >= 37) {
  1052.     struct DosList *dl;
  1053.  
  1054.     dl = AttemptLockDosList(LDF_VOLUMES | LDF_WRITE);
  1055.     /*
  1056.      * Maybe the device list is locked when we are called as a result
  1057.      * of a packet. Don't deadlock on that condition.
  1058.      * Additionally, a hack from the Guru Book p. 393.
  1059.      */
  1060.     if ((ULONG)dl & ~1) {
  1061.         (void)RemDosEntry((struct DosList *)volnode);
  1062.         deallocate = 1;
  1063.         UnLockDosList(LDF_VOLUMES | LDF_WRITE);
  1064.     } else {
  1065.         /*
  1066.          * Failed. Defer to later. If MustFreeVolNode was already set,
  1067.          * that volume is remembered even though it shouldn't.
  1068.          * I hope this is not very likely.
  1069.          */
  1070.         debug(("MustFreeVolNode %lx := %lx\n", MustFreeVolNode, volnode));
  1071.         MustFreeVolNode = volnode;
  1072.     }
  1073.     } else {
  1074.     struct DosInfo *di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
  1075.     struct DeviceList *dl;
  1076.     void  *dlp;
  1077.  
  1078.     dlp = &di->di_DevInfo;
  1079.     Forbid();
  1080.     for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
  1081.         dlp = &dl->dl_Next;
  1082.     if (dl == volnode) {
  1083.         *(BPTR *) dlp = dl->dl_Next;
  1084.         deallocate = 1;
  1085.     }
  1086. #if HDEBUG
  1087.     else {
  1088.         debug(("****PANIC: Unable to find volume node\n"));
  1089.     }
  1090. #endif                /* HDEBUG */
  1091.     Permit();
  1092.     }
  1093.  
  1094.     if (deallocate) {
  1095.     dosfree(BTOC(volnode->dl_Name));
  1096.     dosfree((ulong *)volnode);
  1097.     }
  1098.  
  1099.     if (volnode == VolNode)
  1100.     VolNode = NULL;
  1101. }
  1102.  
  1103. void
  1104. FreeVolNodeDeferred(void)
  1105. {
  1106.     struct DeviceList *tmp = MustFreeVolNode;
  1107.     MustFreeVolNode = NULL;
  1108.     FreeVolNode(tmp);
  1109. }
  1110.  
  1111. /*
  1112.  *  This is also called from the real handler when the last lock on a
  1113.  *  volume is UnLock()ed, or the last file has been Close()d.
  1114.  */
  1115.  
  1116. int
  1117. MayFreeVolNode(volnode)
  1118. struct DeviceList *volnode;
  1119. {
  1120.     if (volnode->dl_LockList == NULL) {
  1121.     FreeVolNode(volnode);
  1122.     return TRUE;
  1123.     }
  1124.  
  1125.     return FALSE;
  1126. }
  1127.  
  1128. #if defined(PROMISE_NOT_TO_DIE)
  1129. /*
  1130.  * This function makes it possible to transfer locks from one handler to
  1131.  * another, when the disk is being moved from one drive to another. The
  1132.  * Amiga file system also does it. Try doing a "list df0:", pause it, put
  1133.  * the disk in df1:, and continue. Unfortunately, passing FileLocks between
  1134.  * handlers assumes that they will stick around forever. Therefore we make
  1135.  * the user promise this by setting the PROMISE_NOT_TO_DIE flag.
  1136.  */
  1137.  
  1138. void RedirectLocks(struct DeviceList *volnode);
  1139. void
  1140. RedirectLocks(volnode)
  1141. struct DeviceList *volnode;
  1142. {
  1143.     if (Interleave & PROMISE_NOT_TO_DIE) {
  1144.     struct FileLock *fl;
  1145.  
  1146.     fl = BTOC(volnode->dl_LockList);
  1147.     while (fl) {
  1148.         /*
  1149.          * This is no good for their OpenCount...
  1150.          * they can never die again!
  1151.          * Alternatively, in DiskRemoved() the OpenCount could
  1152.          * be decremented for each lock (and dl_Task cleared?).
  1153.          */
  1154.         fl->fl_Task = volnode->dl_Task;
  1155.         OpenCount++;
  1156.         fl = BTOC(fl->fl_Link);
  1157.     }
  1158.     }
  1159. }
  1160.  
  1161. #endif
  1162.  
  1163. /*
  1164.  *  Our disk has been removed. Save the FileLocks in the dl_LockList,
  1165.  *  and let the handler save its MSFileLocks in the dl_MSFileLockList field.
  1166.  *  If it has nothing to save, forget about the volume, and return
  1167.  *  DOSTRUE.
  1168.  *  There is one subtlety that MSDiskRemoved must know about:
  1169.  *  If it MSUnLock()s the last lock on the volume, the VolNode is
  1170.  *  deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
  1171.  *  But then there is no place anymore to put NULL in, so that needs
  1172.  *  to be done first.
  1173.  */
  1174.  
  1175. long
  1176. DiskRemoved()
  1177. {
  1178.     debug(("DiskRemoved %08lx\n", VolNode));
  1179.  
  1180. #if INPUTDEV
  1181.     if (IDDiskType != ID_NO_DISK_PRESENT)
  1182.     InputDiskRemoved();
  1183. #endif
  1184.  
  1185.     if (VolNode == NULL) {
  1186.     IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
  1187.     return DOSTRUE;
  1188.     }
  1189.  
  1190.     VolNode->dl_Task = NULL;
  1191.     MSDiskRemoved((struct LockList **)&VolNode->dl_MSFileLockList);
  1192.     if (VolNode == NULL) {  /* Could happen via MSDiskRemoved() */
  1193.     return DOSTRUE;
  1194.     }
  1195.     VolNode = NULL;
  1196.     return DOSFALSE;
  1197. }
  1198.  
  1199. /*
  1200.  *  Reconstruct everything from a Volume node
  1201.  */
  1202.  
  1203. void
  1204. DiskInserted(volnode)
  1205. struct DeviceList *volnode;
  1206. {
  1207.     debug(("DiskInserted %08lx\n", volnode));
  1208.  
  1209.     VolNode = volnode;
  1210.  
  1211.     if (volnode) {
  1212.     volnode->dl_Task = DosPort;
  1213. #if defined(PROMISE_NOT_TO_DIE)
  1214.     RedirectLocks(volnode);
  1215. #endif
  1216.     MSDiskInserted((struct LockList **)&volnode->dl_MSFileLockList, volnode);
  1217.     volnode->dl_MSFileLockList = (BPTR)NULL;
  1218. #if INPUTDEV
  1219.     if (IDDiskType != ID_NO_DISK_PRESENT)
  1220.         InputDiskInserted();
  1221. #endif
  1222.     }
  1223. }
  1224.  
  1225. /*
  1226.  * Test if we have a DD or HD floppy right now.
  1227.  * If the TD_GETDRIVETYPE fails or produces weird values, do nothing.
  1228.  * Otherwise, select the correct sectors/track value, originally
  1229.  * derived from the mountlist.
  1230.  */
  1231. void
  1232. CheckDriveType(void)
  1233. {
  1234.     struct IOExtTD *req = DiskIOReq;
  1235.  
  1236.     debug(("CheckDriveType()\n"));
  1237.     req->iotd_Req.io_Command = TD_GETDRIVETYPE;
  1238.     /*
  1239.      * If this fails or gives weird values, it probably is not
  1240.      * a floppy drive, and we don't mess with the defaults.
  1241.      */
  1242.     if (MyDoIO(&req->iotd_Req) == 0) {
  1243.     int        spt;
  1244.  
  1245.     switch (req->iotd_Req.io_Actual) {
  1246.     case DRIVE3_5:
  1247.     case DRIVE5_25:
  1248.         debug(("DD floppy\n"));
  1249.         spt = Partition.spt_dd;
  1250.         break;
  1251.     case DRIVE3_5_150RPM:
  1252.         debug(("HD floppy\n"));
  1253.         spt = Partition.spt_hd;
  1254.         break;
  1255.     default:
  1256.         debug(("strange drive type: %d\n", req->iotd_Req.io_Actual));
  1257.         goto no_floppy;
  1258.     }
  1259.     DefaultDisk.spt = spt;
  1260.     if (Environ)
  1261.         Environ->de_BlocksPerTrack = spt;
  1262.     DefaultDisk.nsects = (Environ->de_HighCyl - Environ->de_LowCyl + 1) *
  1263.                  DefaultDisk.nsides * spt;
  1264.  
  1265.     /*
  1266.      * Suggest a minimum value for the number of FAT sectors.
  1267.      * Here we assume all sectors are to be used for clusters, which is not
  1268.      * really true, but simpler, and gives a conservative value. Besides,
  1269.      * the number of available sectors also depends on the FAT size, so
  1270.      * the whole calculation (if done correctly) would be recursive. In
  1271.      * practice, it may occasionally suggest one sector too much.
  1272.      */
  1273.     {
  1274.         long        nclusters;
  1275.         long        nbytes;
  1276.  
  1277.         nclusters = MS_FIRSTCLUST + (DefaultDisk.nsects+DefaultDisk.spc-1)/
  1278.                      DefaultDisk.spc;
  1279.         if (nclusters > 0xFF7) /* 16-bit FAT entries */
  1280.         nbytes = nclusters * 2;
  1281.         else          /* 12-bit FAT entries */
  1282.         nbytes = (nclusters * 3 + 1) / 2;
  1283.         DefaultDisk.spf = (nbytes + DefaultDisk.bps - 1) / DefaultDisk.bps;
  1284.         /* Hack for floppies */
  1285.         if (DefaultDisk.spf < MS_SPF)
  1286.         DefaultDisk.spf = MS_SPF;
  1287.     }
  1288.     }
  1289. no_floppy:;
  1290. }
  1291.  
  1292. struct DeviceList *
  1293. WhichDiskInserted()
  1294. {
  1295.     char name[34];
  1296.     struct DateStamp date;
  1297.     struct DeviceList *dl = NULL;
  1298.  
  1299.     CheckDriveType();
  1300.  
  1301.     if (!Inhibited && IdentifyDisk(name, &date) == 0) {
  1302.     struct DosInfo *di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
  1303.     byte           *nodename;
  1304.     int        namelen = strlen(name);
  1305.  
  1306.     for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
  1307.         nodename = BTOC(dl->dl_Name);
  1308.         if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
  1309.         continue;
  1310.         if (dl->dl_VolumeDate == date)  /* Non-standard! Structure compare! */
  1311.         break;
  1312.     }
  1313.  
  1314.     name[31] = '\0';
  1315.     if (dl == NULL)
  1316.         dl = NewVolNode(name, &date);
  1317.     }
  1318.  
  1319.     debug(("WhichDiskInserted() done\n"));
  1320.  
  1321.     return dl;
  1322. }
  1323.  
  1324. void
  1325. DiskChange(void)
  1326. {
  1327.     debug(("DiskChange\n"));
  1328.     DiskChanged = 0;
  1329.     DiskRemoved();
  1330.     DiskInserted(WhichDiskInserted());
  1331. }
  1332.  
  1333. int
  1334. CheckRead(lock)
  1335. struct FileLock *lock;
  1336. {
  1337.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  1338.     error = ERROR_DEVICE_NOT_MOUNTED;
  1339.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  1340.     error = ERROR_NO_DISK;
  1341.     else if (IDDiskType != ID_DOS_DISK)
  1342.     error = ERROR_NOT_A_DOS_DISK;
  1343.  
  1344.     return error;
  1345. }
  1346.  
  1347. int
  1348. CheckWrite(lock)
  1349. struct FileLock *lock;
  1350. {
  1351.     if (CheckRead(lock))
  1352.     /* nothing */ ;
  1353.     else if (IDDiskState == ID_VALIDATING)
  1354.     error = ERROR_DISK_NOT_VALIDATED;
  1355.     else if (IDDiskState != ID_VALIDATED || WriteProtect)
  1356.     error = ERROR_DISK_WRITE_PROTECTED;
  1357.  
  1358.     return error;
  1359. }
  1360.